package com.grace.cms.forum.user.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import com.grace.cms.forum.user.manager.factory.HandAsyncFactory;
import com.grace.cms.forum.user.security.context.AuthenticationContextHolder;
import com.grace.cms.forum.user.security.service.WebUserDetailsService;
import com.grace.common.constant.CacheConstants;
import com.grace.common.constant.Constants;
import com.grace.common.enums.SysConfigGroups;
import com.grace.common.utils.MessageUtils;
import com.grace.common.utils.StringUtils;
import com.grace.redis.utils.RedisCache;
import com.grace.system.service.impl.SysSearchConfigServiceImpl;
import com.grace.cms.general.manager.GeneralAsyncManager;

public class CustomAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

    private WebUserDetailsService userDetailsService;

    @Autowired
    private SysSearchConfigServiceImpl configService;

    @Autowired
    private RedisCache redisCache;


   public CustomAuthenticationProvider(WebUserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
        
    }

    /**
     * additionalAuthenticationChecks
     * 是 Spring Security 中一个核心方法，
     * 用于执行额外的认证检查。
     * 通常，这个方法会在用户名/密码验证之后，但在授权步骤之前被调用。
     */
    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails,
            UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {

    }

    @Override
    protected UserDetails retrieveUser(String username,
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
        // 获取登录提交的验证码
        CustomWebAuthenticationDetails details = (CustomWebAuthenticationDetails) usernamePasswordAuthenticationToken
                .getDetails();

        // 获取验证code
        String validateCode = details.getValidateCode();

        // 获取uuID
        String validateUuid = details.getValidateUuid();

        // 验证开关
        boolean captchaEnabled = configService.selectCaptchaEnabled(SysConfigGroups.SYS_CONFIG.getValue());
        // 验证码开关
        if (captchaEnabled) {
            validateCaptcha(username, validateCode, validateUuid);
        }
        AuthenticationContextHolder.setContext(usernamePasswordAuthenticationToken);
        return userDetailsService.loadUserByUsername(username);
    }

    /**
     * 校验验证码
     * 
     * @param username 用户名
     * @param code     验证码
     * @param uuid     唯一标识
     * @return 结果
     */
    public void validateCaptcha(String username, String code, String uuid) {
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
        String captcha = redisCache.getCacheObject(verifyKey);
        redisCache.deleteObject(verifyKey);
        if (captcha == null) {
            GeneralAsyncManager.me().execute(HandAsyncFactory.recordLogininfor(username, "admin", Constants.LOGIN_FAIL,
                    MessageUtils.message("user.jcaptcha.expire")));
            throw new AccountExpiredException("验证码已经过期");
        }
        if (!code.equalsIgnoreCase(captcha)) {
            GeneralAsyncManager.me().execute(HandAsyncFactory.recordLogininfor(username, "admin", Constants.LOGIN_FAIL,
                    MessageUtils.message("user.jcaptcha.error")));
            throw new CredentialsExpiredException("验证码错误");
        }
    }

}
